package top.aprillie.mamabike.bike.controller;

import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import top.aprillie.mamabike.bike.entity.Bike;
import top.aprillie.mamabike.bike.entity.BikeLocation;
import top.aprillie.mamabike.bike.entity.Point;
import top.aprillie.mamabike.bike.service.BikeGeoService;
import top.aprillie.mamabike.bike.service.BikeService;
import top.aprillie.mamabike.common.constants.Constants;
import top.aprillie.mamabike.common.exception.MaMaBikeException;
import top.aprillie.mamabike.common.resp.ApiResult;
import top.aprillie.mamabike.common.rest.BaseController;

import java.util.List;

/**
 * @Author: illure
 * @Description:
 * @Date: Created in 23:01 2018/2/16
 * @Modified By:
 */
@RestController
@RequestMapping("bike")
@Slf4j
public class BikeController extends BaseController {

    @Autowired
    private BikeService bikeService;

    @Autowired
    private BikeGeoService bikeGeoService;

    /**
     * @Author: illure
     * @Date: 9:35 2018/2/18
     * @Description: 创建单车
     * @Params: []
     * @Return: top.aprillie.mamabike.common.resp.ApiResult<java.lang.String>
     */
    @RequestMapping("/generateBike")
    @ResponseBody
    public ApiResult<String> generateBike() throws MaMaBikeException {
        ApiResult<String> resp = new ApiResult<>();
        try {
            bikeService.generateBike();
            resp.setMessage("创建单车成功");
        } catch (MaMaBikeException e) {
            resp.setCode(e.getStatusCode());
            resp.setMessage(e.getMessage());
        } catch (Exception e) {
            log.error("Fail to update bike info", e);
            resp.setCode(Constants.RESP_STATUS_INTERNAL_ERROR);
            resp.setMessage("内部错误");
        }
        return resp;
    }

    //MongoDB命令
    //db.getCollection('bike-position').find({location : {$nearSphere: {$geometry:{type:"Point",coordinates:[120.515607,30.921101]},$maxDistance:100}},status:1})


    /**
     * @Author: illure
     * @Date: 9:35 2018/2/18
     * @Description: 查找附件单车
     * @Params: [point]
     * @Return: top.aprillie.mamabike.common.resp.ApiResult
     */
    @ApiOperation(value = "查找附近单车", notes = "根据用户APP定位坐标来查找附近单车", httpMethod = "POST")
    @ApiImplicitParam(name = "point", value = "用户定位坐标", required = true, dataType = "Point")
    @RequestMapping("/findAroundBike")
    public ApiResult findAroundBike(@RequestBody Point point) {
        ApiResult<List<BikeLocation>> resp = new ApiResult<>();
        try {
            List<BikeLocation> bikeList = bikeGeoService.geoNear("bike-position", null, point, 10, 50);
            resp.setMessage("查询附近单车成功");
            resp.setData(bikeList);
        } catch (MaMaBikeException e) {
            resp.setCode(e.getStatusCode());
            resp.setMessage(e.getMessage());
        } catch (Exception e) {
            log.error("Fail to find around bike info", e);
            resp.setCode(Constants.RESP_STATUS_INTERNAL_ERROR);
            resp.setMessage("内部错误");
        }
        return resp;
    }

    /**
     * @Author: illure
     * @Date: 9:36 2018/2/18
     * @Description: 解锁单车
     * @Params: [bike]
     * @Return: top.aprillie.mamabike.common.resp.ApiResult
     */
    @ApiOperation(value = "解锁单车", notes = "根据单车编号解锁单车", httpMethod = "POST")
    @ApiImplicitParam(name = "bike", value = "单车编号", required = true, dataType = "Bike")
    @RequestMapping("/unLockBike")
    public ApiResult unLockBike(@RequestBody Bike bike) {
        ApiResult<List<BikeLocation>> resp = new ApiResult<>();
        try {
            bikeService.unLockBike(getCurrentUser(), bike.getNumber());
            resp.setMessage("等待单车解锁");
        } catch (MaMaBikeException e) {
            resp.setCode(e.getStatusCode());
            resp.setMessage(e.getMessage());
        } catch (Exception e) {
            log.error("Fail to unlock bike ", e);
            resp.setCode(Constants.RESP_STATUS_INTERNAL_ERROR);
            resp.setMessage("内部错误");
        }
        return resp;
    }

    /**
     * @Author: illure
     * @Date: 12:32 2018/2/18
     * @Description: 锁车 骑行结束
     * @Params: [bikeLocation]
     * @Return: top.aprillie.mamabike.common.resp.ApiResult
     */
    @ApiOperation(value = "锁定单车", notes = "骑行结束锁定单车（需要上传锁定时候定位坐标）", httpMethod = "POST")
    @ApiImplicitParam(name = "bikeLocation", value = "单车编号", required = true, dataType = "BikeLocation")
    @RequestMapping("/lockBike")
    public ApiResult lockBike(@RequestBody BikeLocation bikeLocation) {
        ApiResult<List<BikeLocation>> resp = new ApiResult<>();
        try {
            bikeService.lockBike(bikeLocation);
            resp.setMessage("锁车成功");
        } catch (MaMaBikeException e) {
            resp.setCode(e.getStatusCode());
            resp.setMessage(e.getMessage());
        } catch (Exception e) {
            log.error("Fail to lock bike", e);
            resp.setCode(Constants.RESP_STATUS_INTERNAL_ERROR);
            resp.setMessage("内部错误");
        }
        return resp;
    }


    /**
     * @Author: illure
     * @Date: 14:24 2018/2/18
     * @Description: 单车上传坐标
     * @Params: [bikeLocation]
     * @Return: top.aprillie.mamabike.common.resp.ApiResult
     */
    @ApiOperation(value = "骑行轨迹上报", notes = "骑行中上报单车位置 轨迹手机卡", httpMethod = "POST")
    @ApiImplicitParam(name = "bikeLocation", value = "单车编号", required = true, dataType = "BikeLocation")
    @RequestMapping("/reportLocation")
    public ApiResult reportLocation(@RequestBody BikeLocation bikeLocation) {
        ApiResult<List<BikeLocation>> resp = new ApiResult<>();
        try {
            bikeService.reportLocation(bikeLocation);
            resp.setMessage("上报坐标成功");
        } catch (MaMaBikeException e) {
            resp.setCode(e.getStatusCode());
            resp.setMessage(e.getMessage());
        } catch (Exception e) {
            log.error("Fail to report location", e);
            resp.setCode(Constants.RESP_STATUS_INTERNAL_ERROR);
            resp.setMessage("内部错误");
        }

        return resp;
    }
}
